local waf={}
local cjson = require "cjson"

local match       = string.match
local ngxmatch    = ngx.re.match
local unescape    = ngx.unescape_uri
local get_headers = ngx.req.get_headers

require 'functions'
math.randomseed(tostring(ngx.time()):reverse():sub(1, 6));

local rulepath = "./waf/wafconf"
local black_fileExt = {".php",".js",".py"}
local urlrules
local argsrules
local postrules

--返回值表示是否发现异常
local function Set (list)
  local set = {}
  for _, l in ipairs(list) do set[l] = true end
  return set
end


local function read_rule(rulename)
    local path = rulepath..'/'..rulename
    ngx.log(ngx.DEBUG,'path=',path)
    local file = io.open(path,"r")
    if file==nil then
        return
    end
    t = {}
    for line in file:lines() do
        table.insert(t,line)
    end
    file:close()
    return t
end

function waf.init()

    urlrules  = read_rule("url")
    argsrules = read_rule("args")
    postrules = read_rule('post')

    --table.dumpdebug(urlrule,'urlrule')
    --table.dumpdebug(argsrules,'argsrules')
    --table.dumpdebug(postrules,'postrules')
end

--检查get的参数是否有问题，返回true表示发现异常
function waf.args()
    for _,rule in pairs(argsrules) do
        local args = ngx.req.get_uri_args()
        for key, val in pairs(args) do
            local data = nil
            if type(val)=='table' then
                local t={}
                for k,v in pairs(val) do
                    if v == true then
                        v=""
                    end
                    table.insert(t,v)
                end
                data=table.concat(t, " ")
            else
                data=val
            end
            --ngx.log(ngx.DEBUG,'rule=',rule,",data=",data)
            if data and type(data) ~= "boolean" and rule ~="" and ngxmatch(unescape(data),rule,"isjo") then
                return true
            end
        end
    end
    return false
end

function waf.url()
    for _,rule in pairs(urlrules) do
        ngx.log(ngx.DEBUG,'GET-',ngx.var.request_uri,"-",rule)
        if rule ~="" and ngxmatch(ngx.var.request_uri,rule,"isjo") then
            --ngx.log(ngx.DEBUG,'GET',ngx.var.request_uri,"-",rule)
            return true
        end
    end
    return false
end

function waf.get_boundary()
    local header = get_headers()["content-type"]
    if not header then
        return nil
    end

    if type(header) == "table" then
        header = header[1]
    end

    local m = match(header, ";%s*boundary=\"([^\"]+)\"")
    if m then
        return m
    end

    return match(header, ";%s*boundary=([^\",;]+)")
end


function waf.body(data)

    for _,rule in pairs(postrules) do
        -- ngx.log(ngx.DEBUG,'POST',"url=",ngx.var.request_uri,",data=",data,",rule=",rule)
        if rule ~="" and data~="" and ngxmatch(unescape(data),rule,"isjo") then
            return true
        end
    end
    return false

end

function waf.fileExtCheck(ext)
    local items = Set(black_fileExt)
    ext=string.lower(ext)
    if ext then
        for rule in pairs(items) do
            if ngx.re.match(ext,rule,"isjo") then
                --ngx.log(ngx.DEBUG,'POST',ngx.var.request_uri,"-","file attack with ext "..ext)
                return true
            end
        end
    end
    return false
end



return waf
